<template>
  <el-form label-width="100px">
    <el-form-item label="SPU名称">
      <el-input placeholder="SPU名称" v-model="spuForm.spuName"></el-input>
    </el-form-item>
    <el-form-item label="品牌">
      <el-select v-model="spuForm.tmId" placeholder="请选择">
        <el-option
          v-for="tm in tmList"
          :key="tm.id"
          :label="tm.tmName"
          :value="tm.id!"
        ></el-option>
      </el-select>
    </el-form-item>
    <el-form-item label="SPU描述">
      <el-input type="textarea" v-model="spuForm.description" :rows="3" placeholder="SPU描述" />
    </el-form-item>

    <el-form-item label="SPU图片">
      
      <el-upload
        v-model:file-list="(spuImageList as any)"
        :action="uploadAction"
        list-type="picture-card"
        :on-success="handlerSuccess"
        :on-preview="handlePictureCardPreview"
        :on-remove="handleRemove"
      >
        <el-icon><Plus /></el-icon>
      </el-upload>
      <el-dialog v-model="dialogVisible">
        <img w-full :src="dialogImageUrl" alt="Preview Image" />
      </el-dialog>

    </el-form-item>

    <el-form-item label="销售属性">
      <div class="mb-10">
        <el-select v-model="saleIdName" class="mr-10" :placeholder="`还有${ saleAttrList.length }个未选择`">
          <el-option
            v-for="saleAttr in saleAttrList"
            :key="saleAttr.id"
            :label="saleAttr.name"
            :value="`${saleAttr.id}:${saleAttr.name}`"
          ></el-option>
        </el-select>
        <el-button type="primary" @click="addSaleAttr">添加销售属性</el-button>
      </div>

      <el-table :data="spuForm.spuSaleAttrList" border size="small">
        <el-table-column type="index" label="序号" width="80" align="center"/>
        <el-table-column label="属性名" prop="saleAttrName" width="200"/>
        <el-table-column label="属性值列表">
          <template #default="{ row, $index }">
            <el-tag
              v-for="(tag,index) in row.spuSaleAttrValueList"
              :key="tag"
              class="mr-5"
              closable
              :disable-transitions="false"
              @close="handleClose(index,row.spuSaleAttrValueList)"
            >
              {{ tag.saleAttrValueName }}
            </el-tag>
            <el-input
              v-if="row.inputVisible"
              ref="InputRef"
              v-model="row.inputValue"
              size="small"
              style="width: 100px;"
              @keyup.enter="handleInputConfirm(row)"
              @blur="handleInputConfirm(row)"
            />
            <el-button v-else class="button-new-tag ml-1" size="small" @click="showInput(row)">
              + 新增
            </el-button>


          </template>
        </el-table-column>
        <el-table-column label="操作" width="80">
          <template #default="{ row, $index }">
            <el-button type="danger" size="small" :icon="Delete" @click="deleteSaleAttr($index)"></el-button>
          </template>
        </el-table-column>
      </el-table>
    </el-form-item>

    <el-form-item>
      <el-button type="primary" @click="onSave">保存</el-button>
      <el-button @click="cancelSave">取消</el-button>
    </el-form-item>
  </el-form>
  
</template>

<script setup lang="ts">
import { ElMessage, type UploadFile, type UploadFiles, type UploadProps, type UploadUserFile } from 'element-plus'
import { Delete, Plus } from '@element-plus/icons-vue'
import { STATUS } from '../../index.vue'
import { computed, nextTick, onMounted, ref } from 'vue'
import trademarkApi, { type TrademarkList } from '@/api/trademark'
import spuApi ,{type SaleAttrModel, type SpuModel , type SpuImageModel , type SpuSaleAttrValueModel, type SpuSaleAttrModel} from '@/api/spu'
import useCategoryStore from '@/stores/category'
import { cloneDeep } from 'lodash'

const uploadAction = `${import.meta.env.VITE_API_URL}/admin/product/upload`

const props = defineProps<{
  modelValue: number,
  spuInfo:SpuModel
}>()

const categoryStore = useCategoryStore()
// defineProps<{
//   modelValue: number
// }>()
const emit = defineEmits<{
  (e: 'update:modelValue', status: number): void
  (e: 'changeSpuInfo'): void
}>()


// 保存的回调
const onSave = async ()=>{
  // 组装数据- 组装保存的时候所需要的数据
  spuForm.value.category3Id = categoryStore.category3Id as number
  // spuName,description,tmId使用的时v-model收集到的
   // 图片数据组装
    // 图片数据使用的是 uploadFiles,这里面放的都是 uploadFile,而uploadFile中有 url 和 name 和 response
    // 其中 url 是本地数据,和我们上传要求的数据格式不一样,需要组装数据
    // imgName
    // imgUrl

  let spuImageListTemp = spuImageList.value.map(item=>{
    return {
      imageName:item.name,
      imgUrl:item.imgUrl || item.response.data  // 只有新上传的图片有response,回显数据的之前上传过的图片是没有的
    }
  })

  spuForm.value.spuImageList = spuImageListTemp as any

  // 把销售属性的 inputVisible 和 inputValue 删除掉（不删也可以，但是接口当中会带着这个数据，带上这个数据不影响后端，但是会影响我们看数据
  spuForm.value.spuSaleAttrList.forEach(row=>{
    delete row.inputVisible
    delete row.inputValue
  })

  // 做简单校验
  let { category3Id, spuName, tmId, description, spuImageList: sIList, spuSaleAttrList} = spuForm.value

  if (!(category3Id && spuName && tmId && description && sIList.length && spuSaleAttrList.length)) {
    ElMessage.error('SPU名称、品牌、三级分类、描述、图片列表、销售属性数据可能为空,请检查输入')
    return
  }

  // 发请求
  try {
    if (spuForm.value.id) {
      await spuApi.updateSpu(spuForm.value)
    } else {
      await spuApi.saveSpu(spuForm.value)
    }
    ElMessage.success('保存成功')
    cancelSave() // 切换到主列表
    // 刷新列表，这个需要在监视的时候添加立即监视
  } catch (error) {
    ElMessage.error('保存失败，请重试')
  }
}

// 取消的回调
const cancelSave = ()=>{
  emit('update:modelValue',STATUS.SPULIST)  // 触发自定义事件，回到列表页
  emit('changeSpuInfo')  // 触发事件清除数据
}








// 收集销售属性
const saleIdName = ref<string>('')
const addSaleAttr = ()=>{
  if (!saleIdName.value) {
    return
  }

  let [id,name] = saleIdName.value.split(':') // 结构出来

  // 为表格添加数据
  spuForm.value.spuSaleAttrList.push({
    baseSaleAttrId:Number(id),
    saleAttrName:name,
    spuSaleAttrValueList:[]
  })

  // 重置收集下拉收集数据的变量
  saleIdName.value = ''
}

// baseSaleAttrList  原始数据  -- 接受接口返回的数据
const saleAttrList = computed(()=>{
  // 在编辑的回显数据的时候，此时编辑的 spu 数据，是著列表中展示 row 这个row.spuSaleAttrList是 null，所以这里需要加判断,进行兼容
  if (!spuForm.value.spuSaleAttrList) {
    return []
  }
  
  // 得到表格中销售属性 id 的数组 ---> [1,2,3]
  let tableSaleIdAttr = spuForm.value.spuSaleAttrList.map(item => item.baseSaleAttrId) 
  // baseSaleAttrList --> [{ id: 1, name: '颜色' }, { id: 2, name: '版本' }, { id: 3, name: '尺码' }]
  // baseSaleAttrList 调用 filter 方法是要返回一个新数据,过滤出符合条件的数据
  //                    符合什么条件?符合在filter参数函数中返回值是true的数据
  return baseSaleAttrList.value.filter(item=>!tableSaleIdAttr.includes(item.id))
})

// 删除属性值
const handleClose = (index:number,spuSaleAttrValueList:SpuSaleAttrValueModel[])=>{
  spuSaleAttrValueList.splice(index,1)
}

// input 回车或者失焦的回调
const handleInputConfirm = (row:SpuSaleAttrModel)=>{
  row.inputVisible = false

  // 判空
  if (!row.inputValue?.trim()) return

  // 判断重复
  if (row.spuSaleAttrValueList.map(item=>item.saleAttrValueName).includes(row.inputValue)) {
    ElMessage.error('输入的属性值重复，请重新输入')
    row.inputValue = ''
    return
  }

  row.spuSaleAttrValueList.push({
    baseSaleAttrId: row.baseSaleAttrId,
    saleAttrValueName: row.inputValue!
  })

  // 当输入的数据添加完成的时候，此时需要把 row.inputValue 清空
  row.inputValue = ''
}

// 获取到 input 框的实例
const InputRef =  ref<HTMLInputElement>()

// 点击新增按钮的回调
const showInput = (row:SpuSaleAttrModel)=>{
  row.inputVisible = true  // 切换input显示
  // 使用nextTick
  nextTick(()=>{
    InputRef.value?.focus()
  })
}

// 删除属性
const deleteSaleAttr = (index:number)=>{
  spuForm.value.spuSaleAttrList.splice(index,1)
}





// 图片上传相关数据和回调
const spuImageList = ref<SpuImageModel[]>([])
const dialogImageUrl = ref('')
const dialogVisible = ref(false)

// 上传成功的回调
const handlerSuccess : UploadProps['onSuccess'] = (response: any, uploadFile: UploadFile, uploadFiles: UploadFiles) => {
  // console.log(response,uploadFile, uploadFiles)


  spuImageList.value = uploadFiles as any
}
// 删除图片的回调
const handleRemove: UploadProps['onRemove'] = (uploadFile, uploadFiles) => {
  // console.log(uploadFile, uploadFiles)
  // 删除是也要为图片列表赋值，是为了能够实时显示
  spuImageList.value = uploadFiles as any
}
// 预览图片的回调，不用动，都是写好的，直接用
const handlePictureCardPreview: UploadProps['onPreview'] = (uploadFile) => {
  dialogImageUrl.value = uploadFile.url!
  dialogVisible.value = true
}
// 



// 当前页面必须有 嚓teforyId 才能打开，后续 要给著列表界面的“添加SPU按钮加限制条件”
const initSpuForm = ():SpuModel=>({
    spuName: '',
    description: '',
    category3Id: categoryStore.category3Id as number,
    tmId: undefined ,
    spuSaleAttrList: [],  // 销售属性列表
    spuImageList: []  
})

const spuForm = ref<SpuModel>(initSpuForm())







// 品牌下拉数据
const tmList = ref<TrademarkList>([])
const getTrademarkData = async ()=>{
  try {
    let result = await trademarkApi.getTrademarkList()
    tmList.value = result
  } catch (error) {
    ElMessage.error('获取品牌下拉数据失败,请重试')
  }
}

// 销售属性下拉数据
const  baseSaleAttrList = ref<SaleAttrModel[]>([])  // 仅仅用作接口一下销售下拉得原始数据,不做展示
const getSaleAttrData = async ()=>{
  try {
    let result = await spuApi.getSaleAttrList()
    baseSaleAttrList.value = result
  } catch (error) {
    ElMessage.error('获取销售属性下拉失败,请重试')
  }
}


// 编辑回显根据 spuId 获取图片列表
const getSpuImageListBySpuId = async ()=>{
  try {
    let result = await spuApi.getSpuImageListBySpuId(props.spuInfo.id!)
    // 图片列表的数据是用了一个单独数据收集的,回显的时候也需要用这个单独的数据
    spuImageList.value = result.map(item=>{
      return {
        ...item,
        name:item.imgName,
        url:item.imgUrl
      }
    })
  } catch (error) {
    ElMessage.error('获取图片列表失败,请重试')
  }
}

// 编辑回显根据spuId获取销售属性列表
 const getSaleAttrListBySpuId = async ()=>{
    try {
      let result = await spuApi.getSpuSaleAttrListBySpuId(props.spuInfo.id!)
      spuForm.value.spuSaleAttrList = result
    } catch (error) {
      ElMessage.error('获取销售属性列表失败,请重试')
    }
 }






// 初始化数据
const initData = ()=>{
  getTrademarkData()
  getSaleAttrData()
  if (props.spuInfo.id) {
    spuForm.value =cloneDeep(props.spuInfo) 
    // 图片列表和销售属性需要发请求拿到
    getSpuImageListBySpuId()
    getSaleAttrListBySpuId()
  }
}

onMounted(()=>{
  initData()
})


// // 关于TS中感叹号使用的场景
// let a: number = 25;
// let b: number | undefined;
// // 这里!的意思:
// //    联合类型中有 number 和 undefine 两个类型
// //    这里将这个联合类型赋值给一个具体的类型number的时候,会飘红
// //    因为不确定这个联合类型是不是undefined
// //    加上!之后,会忽略掉这个类型检测,让 number | undefined 这个联合类型可以直接赋值给 number 类型
// a = b!;
</script>

<style scoped>

</style>